package api

import (
	"context"
	"encoding/json"
	"errors"
	"fmt"
	"gitee.com/go-caipu-team/go-caipu-plugin-sdk/pkg/utils"
	"github.com/gin-gonic/gin"
	"go-caipu/pkg/api/helper"
	"go-caipu/pkg/api/plugin/datasource"
	"go-caipu/pkg/constant"
	"go-caipu/pkg/infra/fs"
	"go-caipu/pkg/plugins"
	"go-caipu/pkg/plugins/log"
	"go-caipu/pkg/services/admin/menu"
	"go-caipu/pkg/services/admin/sysapi"
	"go-caipu/pkg/services/datasources"
	"os"
	"path/filepath"
)

var datasourcesLogger = log.New("datasources")

func (hs *HTTPServer) GetDatasourcePage(c *gin.Context) {
	cmd := datasources.GetDatasourcePageCommand{}
	if err := helper.BindAndValidate(c, &cmd); err != nil {
		return
	}
	result, count, err := hs.dataSourceService.GetDatasourcePage(c.Request.Context(), cmd)
	if err != nil {
		helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
		return
	}
	//SecureJsonData 	禁止前端显示，防止泄漏
	for i := range result {
		result[i].SecureJsonData = "{}"
	}
	helper.SuccessWithData(c, helper.Page{CurrentPage: cmd.PageIndex, PageSize: cmd.PageSize, List: result, Total: count})
}
func (hs *HTTPServer) GetDatasource(c *gin.Context) {
	cmd := datasources.GetDatasourceCommand{}
	if err := helper.BindAndValidate(c, &cmd); err != nil {
		return
	}

	result, err := hs.dataSourceService.GetDataSourceByType(c.Request.Context(), cmd.Id)
	result.SecureJsonData = "{}"
	//获取数据源 如果不存在，则通过插件新增
	if errors.Is(err, datasources.ErrDatasourceNotFound) {
		plugin, exists := hs.pluginStore.Plugin(c.Request.Context(), cmd.Id)
		if !exists {
			helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, errors.New(fmt.Sprintf("plugin %s not exists,not setting data source", cmd.Id)))
			return
		}
		//添加数源源时插入菜单的接口权限（如有）
		result = datasources.Datasource{
			Type:           plugin.ID,
			Version:        "1",
			Name:           plugin.Name,
			JsonData:       []byte("{}"),
			SecureJsonData: "{}",
		}
		result.CreateBy = hs.getJwtUserID(c)
		result.UpdateBy = hs.getJwtUserID(c)
		createDataSource(hs, c, result, plugin)
		return
	}

	if err != nil {
		helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
		return
	}

	helper.SuccessWithData(c, result)

}

// CreateDatasource add datasource
/**
 * @Description: 添加数源源时插入菜单的接口权限（如有）
 * @receiver hs
 * @param c
 * @return
 */
func (hs *HTTPServer) CreateDatasource(c *gin.Context) {
	cmd := datasources.Datasource{}
	if err := helper.BindAndValidate(c, &cmd); err != nil {
		return
	}
	if cmd.Url != "" {
		if err := validateURL(cmd.Type, cmd.Url); err != nil {
			helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
			return
		}
	}
	plugin, exists := hs.pluginStore.Plugin(c.Request.Context(), cmd.Name)
	if !exists {
		helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, errors.New(fmt.Sprintf("plugin %s not exists,not setting data source", cmd.Type)))
		return
	}
	//解密 并进行加密
	var data map[string]string
	encrypt := utils.New(hs.Cfg.Application.EncryptionKey)
	if cmd.SecureJsonData != "" {
		_ = json.Unmarshal([]byte(cmd.SecureJsonData), &data)
		if data != nil {
			for key, value := range data {
				data[key], _ = encrypt.Encrypt(hs.Cfg.DecryptedData(value)) //前端解密，再用加密算法加密
			}
			SecureJsonData, _ := json.Marshal(data)
			cmd.SecureJsonData = string(SecureJsonData)
		}
	}

	createDataSource(hs, c, cmd, plugin)
}
func createDataSource(hs *HTTPServer, c *gin.Context, ds datasources.Datasource, dto plugins.PluginDTO) {
	_, err := hs.dataSourceService.Insert(c.Request.Context(), ds)
	if err != nil {
		helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
		return
	}
	//添加数源源时插入菜单的接口权限（如有）
	err = hs.initPluginMenuAndApi(c.Request.Context(), dto, c)
	if err != nil {
		helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
		return
	}
	helper.SuccessWithData(c, ds)
}
func (hs *HTTPServer) initPluginMenuAndApi(ctx context.Context, dto plugins.PluginDTO, c *gin.Context) error {
	//生成菜单和api接口内容
	operUser := hs.getJwtUserID(c)
	if dto.Type == plugins.DataSource || dto.Type == plugins.App {
		return nil
	}
	apiFile := filepath.Join(hs.Cfg.Application.PluginsPath, dto.ID, "scripts", "sys-api.json")
	exists, _ := fs.Exists(apiFile)
	if exists {
		file, _ := os.Open(apiFile)
		defer file.Close()
		var apiModel []sysapi.ApiCategory
		err := json.NewDecoder(file).Decode(&apiModel)
		if err != nil {
			return err
		}

		//补充导入操作人员
		for _, catetory := range apiModel {
			catetory.OperUser = operUser
		}
		err = hs.apiService.BatchInsert(ctx, apiModel)
		if err != nil {
			return err
		}
		//execute rename file
		return os.Rename(apiFile, apiFile+".end")
	}

	menuFile := filepath.Join(hs.Cfg.Application.PluginsPath, dto.ID, "scripts", "sys-menu.json")
	exists, _ = fs.Exists(menuFile)
	if exists {
		file, _ := os.Open(menuFile)
		defer file.Close()
		var menuModel []menu.Menu
		err := json.NewDecoder(file).Decode(&menuModel)
		if err != nil {
			return err
		}
		//补充菜单导入人员
		for _, menu := range menuModel {
			menu.CreateBy = operUser
			menu.UpdateBy = operUser
		}
		err = hs.menuService.BatchInsert(ctx, menuModel)
		if err != nil {
			return err
		}

		//execute rename file
		return os.Rename(menuFile, menuFile+".end")
	}
	return nil
}
func validateURL(cmdType string, url string) error {
	if _, err := datasource.ValidateURL(cmdType, url); err != nil {
		datasourcesLogger.Error("Failed to validate URL", "url", url)
		return errors.New("Validation error, invalid URL")
	}
	return nil
}

func (hs *HTTPServer) UpdateDatasource(c *gin.Context) {
	cmd := datasources.Datasource{}
	if err := helper.BindAndValidate(c, &cmd); err != nil {
		return
	}
	//解密 并进行加密
	var data map[string]string
	encrypt := utils.New(hs.Cfg.Application.EncryptionKey)
	if cmd.SecureJsonData != "" {
		_ = json.Unmarshal([]byte(cmd.SecureJsonData), &data)
		if data != nil {
			for key, value := range data {
				data[key], _ = encrypt.Encrypt(hs.Cfg.DecryptedData(value)) //前端解密，再用加密算法加密
			}
			SecureJsonData, _ := json.Marshal(data)
			cmd.SecureJsonData = string(SecureJsonData)
		}
	}

	err := hs.dataSourceService.Update(c.Request.Context(), cmd)
	if err != nil {
		helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
		return
	}
	helper.SuccessWithOutData(c)
}

func (hs *HTTPServer) RemoveDatasource(c *gin.Context) {
	cmd := datasources.RemoveDatasourceCommand{}
	if err := helper.BindAndValidate(c, &cmd); err != nil {
		return
	}

	err := hs.dataSourceService.Remove(c.Request.Context(), cmd)
	if err != nil {
		helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
		return
	}
	helper.SuccessWithOutData(c)
}

// RemoveDSByPluginID 删除插件时删除数据源
func (hs *HTTPServer) RemoveDSByPluginID(dto plugins.PluginDTO) error {
	//有菜单和api接口内容
	if dto.Type == plugins.DataSource || dto.Type == plugins.App {
		return nil
	}
	categorys := make([]int64, 0)
	apis := make([]int64, 0)
	menuIds := make([]int64, 0)
	apiFile := filepath.Join(hs.Cfg.Application.PluginsPath, dto.ID, "scripts", "sys-api.json.end")
	exists, _ := fs.Exists(apiFile)
	if exists {
		file, _ := os.Open(apiFile)
		defer file.Close()
		var categorysModel []sysapi.ApiCategory
		err := json.NewDecoder(file).Decode(&categorysModel)
		if err != nil {
			return err
		}
		for _, v := range categorysModel {
			categorys = append(categorys, v.ID)
			for _, api := range v.SysApis {
				apis = append(apis, api.Id)
			}
		}
	}
	menuFile := filepath.Join(hs.Cfg.Application.PluginsPath, dto.ID, "scripts", "sys-menu.json.end")
	exists, _ = fs.Exists(menuFile)
	if exists {
		file, _ := os.Open(menuFile)
		defer file.Close()
		var menuModel []menu.Menu
		err := json.NewDecoder(file).Decode(&menuModel)
		if err != nil {
			return err
		}
		for _, v := range menuModel {
			menuIds = append(menuIds, v.MenuId)
		}
	}
	return hs.dataSourceService.RemoveDSByPluginID(context.Background(), dto.ID, categorys, apis, menuIds)
}

//
//func (hs *HTTPServer) CheckDataSourceHealth(c *gin.Context) {
//	cmd := datasources.GetDatasourceCommand{}
//	cmd.Id = c.Param("name")
//	ds, err := hs.dataSourceService.Get(c.Request.Context(), cmd)
//	if err != nil {
//		helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
//		return
//	}
//	hs.checkDatasourceHealth(c, &ds)
//}
//func (hs *HTTPServer) checkDatasourceHealth(c *gin.Context, ds *datasources.Datasource) {
//	plugin, exists := hs.pluginStore.Plugin(c, ds.Type)
//	if !exists {
//		helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, errors.New("Unable to find datasource plugin"))
//		return
//	}
//	dsInstanceSettings, err := adapters.ModelToInstanceSettings(ds)
//	if err != nil {
//		helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, errors.New("Unable to get datasource model\""))
//		return
//	}
//
//	req := &backend.CheckHealthRequest{
//		PluginContext: backend.PluginContext{
//			PluginID:                   plugin.ID,
//			DataSourceInstanceSettings: dsInstanceSettings,
//		},
//		Headers: map[string]string{},
//	}
//
//	//var dsURL string
//	//if req.PluginContext.DataSourceInstanceSettings != nil {
//	//	dsURL = req.PluginContext.DataSourceInstanceSettings.URL
//	//}
//	//validate ignored
//
//	result, err := hs.pluginClient.CheckHealth(c, req)
//	if err != nil {
//		helper.ErrorWithDetail(c, constant.CodeErrServiceRequestFailed, constant.ErrTypeInternalServer, err)
//		return
//	}
//	if result.Status != backend.HealthStatusOk {
//		helper.ErrorWithDetail(c, constant.CodeErrServiceRequestFailed, constant.ErrTypeInternalServer, errors.New(result.Message))
//		return
//	}
//	helper.SuccessWithData(c, "ok")
//}
